package com.shycloud.mido.member.service.impl;

import com.shycloud.mido.member.service.RegisterService;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shycloud.common.minio.service.MinioTemplate;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.constant.SecurityConstants;
import com.shycloud.mido.common.core.constant.enums.LoginTypeEnum;
import com.shycloud.mido.common.core.exception.BusinessException;
import com.shycloud.mido.common.core.util.R;
import com.shycloud.mido.common.security.util.SecurityUtils;
import com.shycloud.mido.common.sms.service.CloopenSmsService;
import com.shycloud.mido.member.api.dto.MemberDTO;
import com.shycloud.mido.member.api.dto.TeacherApprovalDTO;
import com.shycloud.mido.member.api.entity.LevelSetting;
import com.shycloud.mido.member.api.entity.Member;
import com.shycloud.mido.member.api.entity.MemberDetailInfo;
import com.shycloud.mido.member.api.entity.MemberGoldLog;
import com.shycloud.mido.member.api.entity.MemberIdcard;
import com.shycloud.mido.member.api.entity.MemberLevel;
import com.shycloud.mido.member.api.entity.MemberMoneyLog;
import com.shycloud.mido.member.api.entity.MemberOpinion;
import com.shycloud.mido.member.api.entity.MemberRole;
import com.shycloud.mido.member.api.entity.MemberSign;
import com.shycloud.mido.member.api.entity.MemberStudentInfo;
import com.shycloud.mido.member.api.entity.PointsLog;
import com.shycloud.mido.member.api.entity.TeacherApproval;
import com.shycloud.mido.member.api.entity.TeacherPro;
import com.shycloud.mido.member.api.enums.MessageCodeEnum;
import com.shycloud.mido.member.api.util.Constant;
import com.shycloud.mido.member.api.vo.MemberLevelVO;
import com.shycloud.mido.member.api.vo.MemberVO;
import com.shycloud.mido.member.api.vo.TeacherVO;
import com.shycloud.mido.member.mapper.LevelSettingMapper;
import com.shycloud.mido.member.mapper.MemberDetailInfoMapper;
import com.shycloud.mido.member.mapper.MemberGoldLogMapper;
import com.shycloud.mido.member.mapper.MemberIdcardMapper;
import com.shycloud.mido.member.mapper.MemberLevelMapper;
import com.shycloud.mido.member.mapper.MemberMapper;
import com.shycloud.mido.member.mapper.MemberMoneyLogMapper;
import com.shycloud.mido.member.mapper.MemberOpinionMapper;
import com.shycloud.mido.member.mapper.MemberRoleMapper;
import com.shycloud.mido.member.mapper.MemberSignMapper;
import com.shycloud.mido.member.mapper.MemberStudentInfoMapper;
import com.shycloud.mido.member.mapper.PointsLogMapper;
import com.shycloud.mido.member.mapper.TeacherApprovalMapper;
import com.shycloud.mido.member.mapper.TeacherMapper;
import com.shycloud.mido.member.mapper.TeacherProMapper;
import com.shycloud.mido.member.service.MemberServiceV2;
import com.shycloud.mido.member.service.MobileService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 手机登录相关业务实现
 *
 * @author nianhua.jiang
 * @date 2020/11/16
 */
@Slf4j
@Service
@AllArgsConstructor
public class MobileServiceImpl implements MobileService {

	/** 密码加解密 */
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	/** Redis 服务工具类 */
	private final RedisTemplate redisTemplate;
	/** 验证码服务工具类 */
	private final CloopenSmsService ccpSmsService;

	/** 用户模块 mapper */
	private final MemberMapper memberMapper;
	/** 学生信息模块 mapper */
	private final MemberStudentInfoMapper memberStudentInfoMapper;
	private final MemberIdcardMapper memberIdcardMapper;
	private final MemberDetailInfoMapper memberDetailInfoMapper;
	private final MemberGoldLogMapper memberGoldLogMapper;
	private final MemberMoneyLogMapper memberMoneyLogMapper;
	private final MemberOpinionMapper memberOpinionMapper;
	private final TeacherApprovalMapper teacherApprovalMapper;
	private final TeacherProMapper teacherProMapper;
	private final MinioTemplate minioTemplate;
	private final MemberSignMapper memberSignMapper;
	private final PointsLogMapper pointsLogMapper;
	private final MemberLevelMapper memberLevelMapper;
	private final LevelSettingMapper levelSettingMapper;
	private final TeacherMapper teacherMapper;
	private final CacheManager cacheManager;
	private final MemberRoleMapper memberRoleMapper;
	/** 成功状态码 */
	private static final String SUCCESS = "000000";
	/** 发送数量超出同模板同号天发送次数上限 */
	private static final String ERROR_OVER_COUNT = "160039";
	/** 短信发送频率过快 */
	private static final String ERROR_HIGH_FREQUENCY = "160038";
	/** 会员 service */
	private final MemberServiceV2 memberService;
	/** 注册业务 service */
	private final RegisterService registerService;

	/**
	 * 发送手机登录验证码
	 *
	 * @param mobile
	 * @return com.shycloud.mido.common.core.util.R<java.lang.Boolean>
	 * @author nianhua.jiang
	 * @date 2020/11/16 19:37
	 **/
	@Override
	public R<Boolean> sendSmsCode(String mobile) {

		//验证码前缀规则 ->  DEFAULT_CODE_KEY_SMS@13100000001
		Object codeObj = redisTemplate.opsForValue().get(
				CommonConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + "@" + mobile);

		String ret = "";

		//没过期
		if (codeObj != null) {
			//发送没过期的验证码
			ret = ccpSmsService.sendVerificationCode(mobile, (String) codeObj);
		} else {
			// 生成六位验证码
			String code = RandomUtil.randomNumbers(6);
			log.debug("手机号生成验证码成功:{},{}", mobile, code);
			redisTemplate.opsForValue().set(
					CommonConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + "@" + mobile
					, code, SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
			// 发送验证码
			ret = ccpSmsService.sendVerificationCode(mobile, code);
		}

		//发送数量超出同模板同号天发送次数上限
		if (ERROR_OVER_COUNT.equals(ret)) {
			return new R(Boolean.FALSE, MessageCodeEnum.MORSECODE_ERROR_160039.getMessage());
		}

		//频率过快
		if (ERROR_HIGH_FREQUENCY.equals(ret)) {
			return new R(Boolean.FALSE, MessageCodeEnum.MORSECODE_ERROR_160038.getMessage());
		}

		if (SUCCESS.equals(ret)) {
			return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
		}

		return new R(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_102.getMessage());
	}

	@Override
	public R<Boolean> sendSmsRegisterCode(String mobile) {

		String preStr = "register";
		Object codeObj = redisTemplate.opsForValue().get(
				preStr + "@" + mobile);

		String ret = "";

		//没过期
		if (codeObj != null) {
			//发送没过期的验证码
			ret = ccpSmsService.sendVerificationCode(mobile, (String) codeObj);
		} else {
			// 生成六位验证码
			String code = RandomUtil.randomNumbers(6);
			log.debug("手机号生成验证码成功:{},{}", mobile, code);
			redisTemplate.opsForValue()
					.set(preStr + "@" + mobile, code, SecurityConstants.CODE_TIME,
							TimeUnit.SECONDS);
			// 发送验证码
			ret = ccpSmsService.sendVerificationCode(mobile, code);
		}

		//发送数量超出同模板同号天发送次数上限
		if (ERROR_OVER_COUNT.equals(ret)) {
			return new R(Boolean.FALSE, MessageCodeEnum.MORSECODE_ERROR_160039.getMessage());
		}

		//频率过快
		if (ERROR_HIGH_FREQUENCY.equals(ret)) {
			return new R(Boolean.FALSE, MessageCodeEnum.MORSECODE_ERROR_160038.getMessage());
		}

		if (SUCCESS.equals(ret)) {
			return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
		}

		return new R(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_102.getMessage());
	}

	/**
	 * 手机验证码注册
	 *
	 * @param mobile   用户名
	 * @param password 密码
	 * @param captcha  验证码
	 * @return code
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<Boolean> registerBySmsCode(String mobile, String username, String password,
			String captcha) {
		// 验证用户名
		String reg = "^[0-9a-zA-Z_]{6,18}$";
		Pattern pattern = Pattern.compile(reg);
		Matcher matcher = pattern.matcher(username);

		String regNum = "^[0-9]*$";
		Pattern patternNum = Pattern.compile(regNum);
		Matcher matcherNum = patternNum.matcher(username);

		if (!matcher.matches()) {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_108.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_108.getCode());
		}

		if (matcherNum.matches()) {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_108.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_108.getCode());
		}

		List<Member> memberList = memberMapper.selectList(Wrappers
				.<Member>query().lambda()
				.eq(Member::getUsername, username)
				.eq(Member::getDelFlag, "0"));

		if (!CollUtil.isEmpty(memberList)) {
			log.info("用户名已注册:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_106.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_106.getCode());
		}

		// 验证手机号
		memberList = memberMapper.selectList(Wrappers
				.<Member>query().lambda()
				.eq(Member::getPhone, mobile)
				.eq(Member::getDelFlag, "0"));

		if (!CollUtil.isEmpty(memberList)) {
			log.info("手机号已注册:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_103.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_103.getCode());
		}

		Object codeObj = redisTemplate.opsForValue().get(
				CommonConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + "@" + mobile);

		if (codeObj == null) {
			log.info("手机验证码已过期:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_104.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_104.getCode());
		}
		if (!captcha.equals(codeObj.toString())) {
			log.info("验证码错误:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_105.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_105.getCode());
		}

		Member member = new Member();
		member.setUsername(username);
		member.setShowname(username);
		member.setPassword(ENCODER.encode(password));
		member.setPhone(mobile);
		memberMapper.insert(member);

		// 根据手机号查询用户
		QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("phone", mobile);
		queryWrapper.eq("del_flag", "0");
		Member m = memberMapper.selectOne(queryWrapper);

		// 插入签到信息表
		MemberSign sign = new MemberSign();
		sign.setMemberId(m.getId());
		memberSignMapper.insert(sign);

		// 插入会员等级表
		MemberLevel level = new MemberLevel();
		level.setLevelId("1");
		level.setMemberId(m.getId());
		level.setPoints(0L);
		memberLevelMapper.insert(level);

		//赠送一个月高级VIP
		MemberRole memberRole = new MemberRole();
		memberRole.setMemberId(member.getId());
		memberRole.setRoleCode(Constant.VIP_MEMBER);
		memberRole.setDelFlag(Constant.DEL_FLAG);
		memberRole.setCreateTime(LocalDateTime.now());
		memberRole.setStartTime(LocalDateTime.now());
		memberRole.setEndTime(LocalDateTime.now().plusMonths(1));
		memberRoleMapper.saveMemberRole(memberRole);
		return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 金币消费记录
	 *
	 * @param page     页码
	 * @param memberId 会员ID
	 * @return map
	 */
	@Override
	public R<Map<String, Object>> goldLog(Page page, String memberId) {
		Map<String, Object> map = new HashMap<>();
		List<MemberGoldLog> list = memberGoldLogMapper.goldLog(page, memberId);
		map.put("data", list);
		map.put("next", page.hasNext());
		return new R<>(map, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 会员充值记录
	 *
	 * @param page     页码
	 * @param memberId 会员ID
	 * @return map
	 */
	@Override
	public R<Map<String, Object>> moneyLog(Page page, String memberId) {
		Map<String, Object> map = new HashMap<>();
		List<MemberMoneyLog> list = memberMoneyLogMapper.moneyLog(page, memberId);
		map.put("data", list);
		map.put("next", page.hasNext());
		return new R<>(map, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 上传图片
	 *
	 * @param file 图片文件
	 * @param type 会员ID
	 * @return code
	 */
	@Override
	public R<String> updHeadPhoto(MultipartFile file, String type) {
		// 获取文件的后缀名
		String path = "";
		String url;
		switch (type) {
			//头像
			case "0":
				path = "members/" + "heads/";
				break;
			//省份证
			case "1":
				path = "members/" + "idcard/";
				break;
			//教师证书
			case "2":
				path = "members/" + "cert/";
				break;
			//荣誉证书
			case "3":
				path = "members/" + "honor/";
				break;
			//免冠照片
			case "4":
				path = "members/" + "bareheadedPhoto/";
				break;
			//毕业证书
			case "5":
				path = "members/" + "graduationCertificate/";
				break;
			default:
				break;
		}
		String fileName = path + IdUtil.simpleUUID() + StrUtil.DOT + FileUtil
				.extName(file.getOriginalFilename());
		try {
			url = minioTemplate.uploadFile(file.getInputStream(), fileName);
		} catch (IOException e) {
			log.info("手机验证码已过期:{}", e);
			return new R<>(null, MessageCodeEnum.UPD_MEMBER_HEAD_ERROR_107.getMessage());
		}
		return new R<>(url, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 完善学生信息
	 *
	 * @param memberStudentInfo memberStudentInfo
	 * @return code
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<Boolean> saveStudentInfo(MemberStudentInfo memberStudentInfo) {
		if (memberStudentInfo != null) {
			QueryWrapper<MemberStudentInfo> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("member_id", memberStudentInfo.getMemberId());
			MemberStudentInfo student = memberStudentInfoMapper.selectOne(queryWrapper);
			if (student != null) {
				student.setDuration(memberStudentInfo.getDuration());
				student.setIsGrade(memberStudentInfo.getIsGrade());
				student.setGradeId(memberStudentInfo.getGradeId());
				student.setGradeOrganId(memberStudentInfo.getGradeOrganId());
				memberStudentInfoMapper.updateById(student);
			} else {
				memberStudentInfoMapper.insert(memberStudentInfo);
			}

			// 更新会员表
			Member member = new Member();
			member.setIsStudent("1");
			UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>();
			updateWrapper.eq("id", memberStudentInfo.getMemberId());
			memberMapper.update(member, updateWrapper);
		}
		return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 完善个人信息
	 *
	 * @param memberDTO memberDTO
	 * @return code
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<Boolean> saveMemberInfo(MemberDTO memberDTO) {
		if (memberDTO != null) {
			// 更新会员信息
			Member member = memberMapper.selectById(memberDTO.getId());
			member.setShowname(memberDTO.getShowname());
			member.setRealName(memberDTO.getRealName());
			member.setAvatar(memberDTO.getAvatar());
			memberMapper.updateById(member);

			// 更新会员详细信息
			QueryWrapper<MemberDetailInfo> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("member_id", memberDTO.getId());
			MemberDetailInfo detail = memberDetailInfoMapper.selectOne(queryWrapper);

			if (detail == null) {
				detail = new MemberDetailInfo();
			}
			detail.setSex(memberDTO.getSex());
			detail.setBirthday(memberDTO.getBirthday());
			detail.setProvince(memberDTO.getProvince());
			detail.setProvinceId(memberDTO.getProvinceId());
			detail.setCity(memberDTO.getCity());
			detail.setCityId(memberDTO.getCityId());
			detail.setAddress(memberDTO.getAddress());
			detail.setSignature(memberDTO.getSignature());

			if (StrUtil.isNotEmpty(detail.getMemberId())) {
				memberDetailInfoMapper.updateById(detail);
			} else {
				detail.setMemberId(memberDTO.getId());
				memberDetailInfoMapper.insert(detail);
			}
		}
		return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 微信登录
	 *
	 * @param openid 微信号
	 * @return code
	 */
	@Override
	public R<Boolean> wxLogin(String openid) {
		// 查询微信号是否存在
		QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("wx_openid", openid).eq("del_flag", "0");
		Member member = memberMapper.selectOne(queryWrapper);
		if (member != null) {
			return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
		} else {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_110.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_110.getCode());
		}
	}

	/**
	 * 微信绑定系统账号
	 *
	 * @param openid  微信号
	 * @param mobile  手机号
	 * @param captcha 验证码
	 * @return code
	 */
	@Override
	public R<Boolean> wxBind(String openid, String mobile, String captcha) {
		Object codeObj = redisTemplate.opsForValue().get(
				CommonConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + "@" + mobile);

		if (codeObj == null) {
			log.info("手机验证码已过期:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_104.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_104.getCode());
		}
		if (!captcha.equals(codeObj.toString())) {
			log.info("验证码错误:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_105.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_105.getCode());
		}

		QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("phone", mobile).eq("del_flag", "0");
		Member member = memberMapper.selectOne(queryWrapper);
		if (member == null) {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_115.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_115.getCode());
		}
		if (StrUtil.isNotEmpty(member.getWxOpenid())) {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_116.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_116.getCode());
		}

		member.setWxOpenid(openid);
		member.setIsWxAuth("1");
		memberMapper.updateById(member);

		return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 微信绑定注册账号
	 *
	 * @param openid   微信号
	 * @param mobile   手机号
	 * @param username 用户名
	 * @param password 密码
	 * @return code
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<Boolean> wxRegister(String openid, String mobile, String username, String password) {
		// 验证用户名
		String reg = "^[0-9a-zA-Z_]{6,18}$";
		Pattern pattern = Pattern.compile(reg);
		Matcher matcher = pattern.matcher(username);

		String regNum = "^[0-9]*$";
		Pattern patternNum = Pattern.compile(regNum);
		Matcher matcherNum = patternNum.matcher(username);

		if (!matcher.matches()) {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_108.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_108.getCode());
		}

		if (matcherNum.matches()) {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_108.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_108.getCode());
		}

		List<Member> memberList = memberMapper.selectList(Wrappers
				.<Member>query().lambda()
				.eq(Member::getUsername, username)
				.eq(Member::getDelFlag, "0"));

		if (!CollUtil.isEmpty(memberList)) {
			log.info("用户名已注册:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_106.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_106.getCode());
		}

		// 验证手机号
		memberList = memberMapper.selectList(Wrappers
				.<Member>query().lambda()
				.eq(Member::getPhone, mobile)
				.eq(Member::getDelFlag, "0"));

		if (!CollUtil.isEmpty(memberList)) {
			log.info("手机号已注册:{}", mobile);
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_103.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_103.getCode());
		}

		Member member = new Member();
		member.setUsername(username);
		member.setShowname(username);
		member.setPassword(ENCODER.encode(password));
		member.setPhone(mobile);
		member.setWxOpenid(openid);
		member.setIsMobileAuth("1");
		member.setIsWxAuth("1");
		memberMapper.insert(member);

		// 根据手机号查询用户
		QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("phone", mobile);
		Member m = memberMapper.selectOne(queryWrapper);

		// 插入签到信息表
		MemberSign sign = new MemberSign();
		sign.setMemberId(m.getId());
		memberSignMapper.insert(sign);

		// 插入会员等级表
		MemberLevel level = new MemberLevel();
		level.setLevelId("1");
		level.setMemberId(m.getId());
		level.setPoints(0L);
		memberLevelMapper.insert(level);

		//增加积分--首次注册
		//activeMechanismService.activePoints(Constant.FIRST_REGISTER,member.getId());

		//增加积分--首次登录
		//activeMechanismService.activePoints(Constant.FIRST_LOGIN,member.getId());

		//赠送一个月高级VIP
		MemberRole memberRole = new MemberRole();
		memberRole.setMemberId(member.getId());
		memberRole.setRoleCode(Constant.VIP_MEMBER);
		memberRole.setDelFlag(Constant.DEL_FLAG);
		memberRole.setCreateTime(LocalDateTime.now());
		memberRole.setStartTime(LocalDateTime.now());
		memberRole.setEndTime(LocalDateTime.now().plusMonths(1));
		memberRoleMapper.saveMemberRole(memberRole);
		return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
	}


	/**
	 * 获取关联学生列表
	 *
	 * @param userid 会员id
	 * @return R
	 */
	@Override
	public R getStudentList(String userid) {
		return new R<>(memberMapper.getAssociatedStudents(userid),
				MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 获取用户信息
	 *
	 * @param userid 会员id
	 * @return R
	 */
	@Override
	public R<MemberVO> getMemberInfo(String userid) {
		// 查询是否家长
		List<Member> studentList = memberMapper.getAssociatedStudents(userid);

		MemberVO member = memberMapper.getMemberVoById(userid);
		if (member != null) {
			if (studentList.size() > 0) {
				member.setIsParent("1");
			} else {
				member.setIsParent("0");
			}
			return new R<>(member, MessageCodeEnum.SUCCESS.getMessage());
		} else {
			return new R<>(member, MessageCodeEnum.MEMBER_ERROR_109.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_109.getCode());
		}
	}

	/**
	 * 获取用户实名认证信息
	 *
	 * @param userid 会员id
	 * @return R
	 */
	@Override
	public R<MemberIdcard> getMemberIdcard(String userid) {
		QueryWrapper<MemberIdcard> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("member_id", userid);
		return new R<>(memberIdcardMapper.selectOne(queryWrapper),
				MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 绑定会员
	 *
	 * @param parentId  家长id
	 * @param studentId 学生id
	 * @return code
	 */
	@Override
	public R<Boolean> bindMember(String parentId, String studentId) {
		if (StrUtil.isNotEmpty(memberMapper.isBinded(parentId, studentId))) {
			return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_114.getMessage())
					.setCode(MessageCodeEnum.MEMBER_ERROR_114.getCode());
		}
		return new R<>(memberMapper.bindMember(parentId, studentId),
				MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 解绑会员
	 *
	 * @param parentId  家长id
	 * @param studentId 学生id
	 * @return code
	 */
	@Override
	public R<Boolean> unbindMember(String parentId, String studentId) {
		return new R<>(memberMapper.unbindMember(parentId, studentId),
				MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 签到
	 *
	 * @param userid 会员id
	 * @return code
	 */
	@Override
	public R<Boolean> signIn(String userid) {
		return new R<>(memberMapper.signIn(userid), MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 修改密码
	 *
	 * @param mobile      手机号
	 * @param captcha     验证码
	 * @param newpassword 新密码
	 */
	@Override
	public R<Boolean> changePassword(String mobile, String captcha, String newpassword) {
		String superCaptcha = "";
		Object superCodeObj = redisTemplate.opsForValue().get("superCaptcha");
		if (superCodeObj == null) {
			log.info("超级验证码已过期:{}", mobile);
		} else {
			superCaptcha = superCodeObj.toString();
		}
		Member member = memberMapper.selectOne(Wrappers
				.<Member>query().lambda().eq(Member::getUsername, mobile).eq(Member::getDelFlag, "0"));
		if (member != null) {
			if (superCaptcha.isEmpty() || !captcha.equals(superCaptcha)) {
				Object codeObj = redisTemplate.opsForValue().get(
						CommonConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + "@"
								+ mobile);
				if (codeObj == null) {
					log.info("手机验证码已过期:{}", mobile);
					return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_104.getMessage())
							.setCode(MessageCodeEnum.MEMBER_ERROR_104.getCode());
				}
				if (!captcha.equals(codeObj.toString())) {
					log.info("验证码错误:{}", mobile);
					return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_105.getMessage())
							.setCode(MessageCodeEnum.MEMBER_ERROR_105.getCode());
				}
			}
			member.setPassword(ENCODER.encode(newpassword));
			Cache cache = cacheManager.getCache("member_details");
			cache.evict(member.getUsername());
			cache.evict(mobile);
			memberMapper.updateById(member);
			return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
		}
		return new R<>(Boolean.FALSE, MessageCodeEnum.MEMBER_ERROR_117.getMessage());
	}

	/**
	 * 意见反馈
	 *
	 * @param memberOpinion memberOpinion
	 * @return code
	 */
	@Override
	public Boolean saveOpinion(MemberOpinion memberOpinion) {
		memberOpinion.setMemberId(SecurityUtils.getMember().getId());
		return memberOpinionMapper.insert(memberOpinion) == 1;
	}


	/**
	 * 绑定手机
	 *
	 * @param mobile
	 * @param captcha
	 * @return com.shycloud.mido.common.core.util.R<java.lang.Boolean>
	 * @author nianhua.jiang
	 * @date 2020/9/4 17:34
	 **/
	@Override
	public Boolean bindPhone(String mobile, String captcha, String openId) {

		Boolean registerRedis = redisTemplate.opsForValue()
				.setIfAbsent("register_" + mobile, "1", 5, TimeUnit.SECONDS);

		if (!registerRedis) {
			throw new BusinessException("该账号已经绑定，无需重复绑定。");
		}

		//判断验证码是否正确
		Object codeObj = redisTemplate.opsForValue().get(
				CommonConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + "@" + mobile);

		if (codeObj == null) {
			redisTemplate.delete("register_" + mobile);
			throw new BusinessException("手机验证码已过期");
		}
		if (!captcha.equals(codeObj.toString())) {
			redisTemplate.delete("register_" + mobile);
			throw new BusinessException("验证码错误");
		}

		//绑定手机
		Member member = memberMapper.selectOne(new QueryWrapper<Member>().eq("username", mobile));

		if (member == null) {
			//如果member为空则新建用户
			registerService.wxRegister(mobile, openId);
			return true;
		} else {
			if ("9".equals(member.getLockFlag())) {
				redisTemplate.delete("register_" + mobile);
				throw new BusinessException("该账号已被绑定");
			}

			if (member.getWxOpenid() != null) {
				redisTemplate.delete("register_" + mobile);
				throw new BusinessException("此微信号已于其他账号绑定，请绑定其他手机号");
			}

			//绑定openId
			member.setWxOpenid(openId);
			return memberMapper.updateById(member) == 1;
		}

	}

	/**
	 * 认证教师
	 *
	 * @param teacherApprovalDTO teacherApprovalDTO
	 * @return code
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<Boolean> approveTeacher(TeacherApprovalDTO teacherApprovalDTO) {
		if (teacherApprovalDTO != null) {
			// 更新平台认证教师表
			QueryWrapper<TeacherApproval> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("member_id", teacherApprovalDTO.getMemberId());
			teacherApprovalMapper.delete(queryWrapper);

			TeacherApproval teacherApproval = new TeacherApproval();
			teacherApproval.setMemberId(teacherApprovalDTO.getMemberId());
			teacherApproval.setScope(teacherApprovalDTO.getScope());
			teacherApproval.setSex(teacherApprovalDTO.getSex());
			teacherApproval.setHeadPic(teacherApprovalDTO.getHeadPic());
			teacherApproval.setSchool(teacherApprovalDTO.getSchool());
			teacherApproval.setDegree(teacherApprovalDTO.getDegree());
			teacherApproval.setDegreePic(teacherApprovalDTO.getDegreePic());
			teacherApproval.setTeacherPic(teacherApprovalDTO.getTeacherPic());
			teacherApproval.setIntroduction(teacherApprovalDTO.getIntroduction());
			teacherApproval.setStatus("0");
			teacherApprovalMapper.insert(teacherApproval);

			// 更新教师荣誉证书表
			QueryWrapper<TeacherPro> queryProWrapper = new QueryWrapper<>();
			queryProWrapper.eq("member_id", teacherApprovalDTO.getMemberId());
			teacherProMapper.delete(queryProWrapper);

			String proPic = teacherApprovalDTO.getProPic();
			if (StrUtil.isNotEmpty(proPic)) {
				String[] proArray = proPic.split(",");
				for (String s : proArray) {
					TeacherPro teacherPro = new TeacherPro();
					teacherPro.setMemberId(teacherApprovalDTO.getMemberId());
					teacherPro.setProPic(s);
					teacherProMapper.insert(teacherPro);
				}
			}

			// 更新教师科目关系表
//			QueryWrapper<TeacherSubject> querySubjectWrapper = new QueryWrapper<>();
//			querySubjectWrapper.eq("member_id", teacherApprovalDTO.getMemberId());
//			teacherSubjectMapper.delete(querySubjectWrapper);

//			String subjects = teacherApprovalDTO.getSubjects();
//			if (StrUtil.isNotEmpty(subjects)) {
//				String[] subjectArray = subjects.split(",");
//				for (String s : subjectArray) {
//					TeacherSubject teacherSubject = new TeacherSubject();
//					teacherSubject.setMemberId(teacherApprovalDTO.getMemberId());
//					teacherSubject.setSubjectId(s);
//					teacherSubjectMapper.insert(teacherSubject);
//				}
//			}

			// 更新身份证信息表
			QueryWrapper<MemberIdcard> queryIdcardWrapper = new QueryWrapper<>();
			queryIdcardWrapper.eq("member_id", teacherApprovalDTO.getMemberId());
			memberIdcardMapper.delete(queryIdcardWrapper);

			MemberIdcard memberIdcard = new MemberIdcard();
			memberIdcard.setMemberId(teacherApprovalDTO.getMemberId());
			memberIdcard.setRealName(teacherApprovalDTO.getRealName());
			memberIdcard.setIdType(teacherApprovalDTO.getIdType());
			memberIdcard.setIdNumber(teacherApprovalDTO.getIdNumber());
			memberIdcard.setFrontPic(teacherApprovalDTO.getFrontPic());
			memberIdcard.setBackPic(teacherApprovalDTO.getBackPic());
			memberIdcard.setCreateTime(LocalDateTime.now());
			memberIdcardMapper.insert(memberIdcard);

			// 更新会员表
			Member member = new Member();
			member.setRealName(teacherApprovalDTO.getRealName());
			member.setIsTeacher("2");
			UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>();
			updateWrapper.eq("id", teacherApprovalDTO.getMemberId());
			memberMapper.update(member, updateWrapper);
		}
		return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 获取会员考级信息
	 *
	 * @param userid 会员id
	 * @return R
	 */
	@Override
	public R<MemberStudentInfo> getStudentInfo(String userid) {
		QueryWrapper<MemberStudentInfo> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("member_id", userid);
		MemberStudentInfo memberStudentInfo = memberStudentInfoMapper.selectOne(queryWrapper);
		return new R<>(memberStudentInfo, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 获取教师信息
	 *
	 * @param userid 会员id
	 * @return R
	 */
	@Override
	public R<TeacherApprovalDTO> getTeacherInfo(String userid) {
		// 获取平台认证教师信息
		QueryWrapper<TeacherApproval> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("member_id", userid);
		TeacherApproval teacherApproval = teacherApprovalMapper.selectOne(queryWrapper);

		// 获取教师身份证信息
		QueryWrapper<MemberIdcard> queryIdcardWrapper = new QueryWrapper<>();
		queryIdcardWrapper.eq("member_id", userid);
		MemberIdcard idcard = memberIdcardMapper.selectOne(queryIdcardWrapper);

//		// 获取教师科目信息
//		QueryWrapper<TeacherSubject> querySubjectWrapper = new QueryWrapper<>();
//		querySubjectWrapper.eq("member_id", userid);
//		List<TeacherSubject> teacherSubjects = teacherSubjectMapper.selectList(querySubjectWrapper);
//
//		StringBuilder subjects = new StringBuilder();
//		for (TeacherSubject teacherSubject : teacherSubjects) {
//			subjects.append(teacherSubject.getSubjectId()).append(",");
//		}

		// 获取教师荣誉证书
		QueryWrapper<TeacherPro> queryProWrapper = new QueryWrapper<>();
		queryProWrapper.eq("member_id", userid);
		List<TeacherPro> teacherPros = teacherProMapper.selectList(queryProWrapper);

		StringBuilder pros = new StringBuilder();
		for (TeacherPro teacherPro : teacherPros) {
			pros.append(teacherPro.getProPic()).append(",");
		}
		TeacherApprovalDTO teacherApprovalDTO = new TeacherApprovalDTO();
//		if (subjects.length() > 0) {
//			teacherApprovalDTO.setSubjects(subjects.substring(0, subjects.length() - 1));
//		}
		if (teacherApproval != null) {
			teacherApprovalDTO.setScope(teacherApproval.getScope());
			teacherApprovalDTO.setSex(teacherApproval.getSex());
			teacherApprovalDTO.setHeadPic(teacherApproval.getHeadPic());
			teacherApprovalDTO.setSchool(teacherApproval.getSchool());
			teacherApprovalDTO.setDegree(teacherApproval.getDegree());
			teacherApprovalDTO.setDegreePic(teacherApproval.getDegreePic());
			teacherApprovalDTO.setTeacherPic(teacherApproval.getTeacherPic());
			teacherApprovalDTO.setIntroduction(teacherApproval.getIntroduction());
		}
		if (idcard != null) {
			teacherApprovalDTO.setRealName(idcard.getRealName());
			teacherApprovalDTO.setIdType(idcard.getIdType());
			teacherApprovalDTO.setIdNumber(idcard.getIdNumber());
			teacherApprovalDTO.setFrontPic(idcard.getFrontPic());
			teacherApprovalDTO.setBackPic(idcard.getBackPic());
		}
		if (pros.length() > 0) {
			teacherApprovalDTO.setProPic(pros.substring(0, pros.length() - 1));
		}

		return new R<>(teacherApprovalDTO, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 积分日志
	 *
	 * @param page     页码
	 * @param memberId 会员ID
	 * @return map
	 */
	@Override
	public R<Map<String, Object>> pointsLog(Page page, String memberId) {
		Map<String, Object> map = new HashMap<>();
		List<PointsLog> list = pointsLogMapper.pointsLog(page, memberId);
		map.put("data", list);
		map.put("next", page.hasNext());
		return new R<>(map, MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 是否签到
	 *
	 * @param userid 会员id
	 * @return code
	 */
	@Override
	public R<Boolean> isSigned(String userid) {
		QueryWrapper<MemberSign> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("member_id", userid);
		MemberSign memberSign = memberSignMapper.selectOne(queryWrapper);

		if (memberSign.getTotalCont() == 0) {
			return new R<>(Boolean.FALSE);
		}

		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		String signDate = dtf.format(memberSign.getUpdateTime());
		String today = dtf.format(LocalDateTime.now());
		if (signDate.equals(today)) {
			return new R<>(Boolean.TRUE, MessageCodeEnum.SUCCESS.getMessage());
		} else {
			return new R<>(Boolean.FALSE);
		}
	}

	/**
	 * 获取用户经验值
	 *
	 * @param userid 会员id
	 * @return R
	 */
	@Override
	public R<MemberLevelVO> getLevel(String userid) {
		return new R<>(memberLevelMapper.getMemberLevelVoById(userid),
				MessageCodeEnum.SUCCESS.getMessage());
	}

	/**
	 * 获取会员等级列表
	 *
	 * @return R
	 */
	@Override
	public R<List<LevelSetting>> levelSetting() {
		QueryWrapper<LevelSetting> queryWrapper = new QueryWrapper<>();
		return new R<>(levelSettingMapper.selectList(queryWrapper));
	}

	/**
	 * 获取教师信息表信息
	 *
	 * @param memberId 会员id
	 * @return R
	 */
	@Override
	public R<TeacherVO> getTeacher(String memberId) {
		return new R<>(teacherMapper.getTeacher(memberId));
	}

	/**
	 * 查询教师证书照片
	 *
	 * @param memberId memberId
	 * @return
	 */
	@Override
	public List<String> getTeacherProPic(String memberId) {
		return teacherMapper.getTeacherProPic(memberId);
	}

	/**
	 * 查询教师科目Id
	 *
	 * @param memberId memberId
	 * @return
	 */
	@Override
	public List<String> getTeacherSubjectId(String memberId) {
		return teacherMapper.getTeacherSubjectId(memberId);
	}


	/**
	 * 查询联系签到天数
	 *
	 * @param memberId
	 * @return
	 */
	@Override
	public int selSignCount(String memberId) {
		return memberSignMapper.selSignCount(memberId);
	}

	/**
	 * 忘记密码
	 *
	 * @param phone
	 * @param pwd
	 * @return int
	 * @author nianhua.jiang
	 * @date 2020/6/29 13:44
	 */
	@Override
	public int forgetPwd(String phone, String pwd) {

		//根据phone获取用户信息
		Member member = memberMapper.selectOne(new QueryWrapper<Member>()
				.eq("phone", phone));

		//member信息为空
		if (member == null) {
			return 2;
		} else {
			//密码
			member.setPassword(ENCODER.encode(pwd));
			//更新日期
			member.setUpdateTime(LocalDateTime.now());
			//更新
			return memberMapper.updateById(member);
		}
	}

	@Override
	public Boolean iosBindPhone(String mobile, String captcha, String userId) {

		Boolean registerRedis = redisTemplate.opsForValue()
				.setIfAbsent("register_" + mobile, "1", 5, TimeUnit.SECONDS);

		if (!registerRedis) {
			throw new BusinessException("该账号已经绑定，无需重复绑定。");
		}

		//判断验证码是否正确
		Object codeObj = redisTemplate.opsForValue().get(
				CommonConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + "@" + mobile);

		if (codeObj == null) {
			redisTemplate.delete("register_" + mobile);
			throw new BusinessException("手机验证码已过期");
		}
		if (!captcha.equals(codeObj.toString())) {
			redisTemplate.delete("register_" + mobile);
			throw new BusinessException("验证码错误");
		}

		//判断手机号是否使用
		Integer phone = memberMapper.selectCount(new QueryWrapper<Member>().eq("phone", mobile));

		if (phone > 0) {
			throw new BusinessException("此手机号已与其他账号绑定，请重新绑定~~");
		}

		Integer username = memberMapper
				.selectCount(new QueryWrapper<Member>().eq("username", mobile));

		if (username > 0) {
			throw new BusinessException("此手机号已与其他账号绑定，请重新绑定~~");
		}

		//绑定手机
		Member member = memberMapper.selectById(userId);

		member.setUsername(mobile);
		member.setPhone(mobile);

		return memberMapper.updateById(member) == 1;
	}
}

